
#include<stdarg.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<time.h>
#include<sys/time.h>
#include<sys/file.h>
#include<sys/types.h>
#include<errno.h>
#include<libgen.h>
#include"../include/client.h"

#ifndef LOGLEVEL
#define LOGLEVEL DEBUG
#endif

#define MAXSIZE_LOG 1024//日志文件的大小


//gcc扩展语法,通过s_loginfo数组即可获取等级对应的字符串
static const char* s_loginfo[] = 
{
/*  
        [ERROR] = "ERROR",
        [WARN]  = "WARN",
        [INFO]  = "INFO",
        [DEBUG] = "DEBUG",
*/
    "ERROR","WARN","INFO","DEBUG"
};

/* 测试程序 
 * */
/* int main(int argc,char **argv)
{
    mylog(__func__,__LINE__,DEBUG,"this is debug information");

    mylog(__func__,__LINE__,INFO,"this is info information");

    
    mylog(__func__,__LINE__,WARN,"this is warn information");


    mylog(__func__,__LINE__,ERROR,"this is error information");

}
*/

int mylog(const char *function, int line, enum LogLevel level, const char *fmt, ...)//含有可变参数的函数
{
        time_t         t;
        struct tm      *p;
        struct timeval tv;
        FILE           *fp;
        char           buf[100];
        char           log_buf[200];
        char           time_buf[32];
        va_list        arg_list;
        int            millisec;
        off_t          filesize;
        int            fd = -1;//文件描述符
        
        memset(buf,0,sizeof(buf));
       
        //开始应用可变参数
        va_start(arg_list,fmt);//指向可变参数表中的第一个参数
        vsnprintf(buf,sizeof(buf),fmt,arg_list);//将可变参数输出到buf中
        
	    //获取事件戳
        t = time(NULL);
        p = localtime(&t);

        gettimeofday(&tv,NULL);
        millisec = (int)(tv.tv_usec/100);

        //制作时间的格式：年月日时分秒毫秒
        snprintf(time_buf,32,"%04d-%02d-%02d %02d:%02d:%02d:%03d",p->tm_year+1900,p->tm_mon+1,p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec,millisec);
        

        if(level > LOGLEVEL)//日志等级不存在则返回
                return -1;

        //制作日志格式：时间+函数+行+信息
        snprintf(log_buf,sizeof(buf),"[%s][%s][%s:%d]:%s",time_buf,s_loginfo[level], function, line, buf);
        
        //打开或者创建日志文件
        if((fp = fopen("mylog.txt","a+"))==NULL)
        {
                printf("fopen mylog.txt failed:%s\n",strerror(errno));
                return -1;
        }


        fd = fileno(fp);//文件指针转化为文件描述符
        if(fd < 0)
        {
            printf("fileno error:%s\n",strerror(errno));
            return -1;
        }
        //给日志文件上锁，防止在并发程序中共用日志文件
        if(flock(fd,LOCK_EX) ==-1 )
        {
            printf("flock LOCK_EX failed:%s\n",strerror(errno));
            return -1;
        }
        
        //刚打开文件的时候文件指针默认在文件头，所以先将文件指针偏移到文件尾
        if((filesize=lseek(fd,0,SEEK_END)) ==-1 )
        {
            printf("lseek failed:%s\n",strerror(errno));
            return -1;
        }
        
        //控制文件不要无限制增长，设置文件最大容量，到达就清空
        if(filesize == MAXSIZE_LOG)
        {
            if(ftruncate(fd,0) ==-1 )//清空文件
            {
                printf("ftruncate failed:%s\n",strerror(errno));
                return -1;
            }
        }
        
        //调用库函数将日志信息写入日志文件
        fprintf(fp,"%s\n",log_buf);

        //可变参数的应用区结束
        va_end(arg_list);

        //释放文件锁
        if(flock(fd,LOCK_UN) ==-1 )
        {
            printf("flock LOCK_UN failed:%s\n",strerror(errno));
            return -1;
        }

        //关闭文件流描述符
        fclose(fp);

        return 0;

}
